/****************************************************************************/
/*                                                                          */
/*   FILE:    transcod.c	                                                */
/*   DATE:    13/06/97                                                      */
/*   PURPOSE: DVB-CI Transport layer - TPDU Coding/Decoding Module			*/
/*			  conform to DVB-CI prEN 50221, june 1996						*/ 	
/*   TAB STOPS : 4															*/
/*   HISTORY:				                                 			    */
/*   Version    Date  		    Written by	     Notes	    	    		*/
/*	 1.0	    13/06/1997      SCM              Initial implementation 	*/
/*   1.5        29/12/1998      SCM            In function TRPT_SetLength() */
/*           the way to encode the length, if greater than 255, is modified */
/*                                             In function TRPT_GetLength() */
/*           the way to decode the length, if coded on 2 chars, is mofified */
/*                                                                    	    */
/*--------------------------------------------------------------------------*/
/*   GENERAL COMMENTS                                                 	    */
/*		This module codes and decodes TPDU									*/
/*																		    */
/****************************************************************************/
#include <stdio.h>
#include <memory.h>
#include "sm_trace.h"
#include "itc.h"
#include "trans.h"			


extern trn_fifo_t g_trn_tab_fifo[];

/* ======================================================================== */
/* NAME : TRPT_Code						 									*/
/* 									    									*/
/* DESCRIPTION : code a TPDU												*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		tpduTag		: type of TPDU												*/
/*		tcid	: transport connection										*/
/*		pXpdu	: parameters dependent of the tpduTag							*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*		tpdu	: pointer to coded TPDU	buffer								*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : error while coding											*/
/*		> 0 : length of coded TPDU											*/
/*									  										*/
/* ======================================================================== */
int TRPT_Code(unsigned char tpduTag, unsigned char tcid, xpdu_t *pXpdu, unsigned char *pbTpdu)
{
	int iRet = 0;				/* return code 				   */
	unsigned char *ptr;	    /* pointer to allocated memory */
	unsigned short lenlen;				/* length of t_data_last / t_data_more length field	  */

	SM_TRACE_ENTRY(TRMOD_TRANS, "TRPT_Code() - entry,tpduTag=%s(0x%02X),tcid=%d,pbTpdu=0x%08X,pXpdu=0x%08X\r\n",
					XMSG_NAME(tpduTag), tpduTag, tcid, pbTpdu, pXpdu);

	ptr = pbTpdu;		    /* points the allocated buffer */

	/* Coding */			
	switch (tpduTag)
	{
	case t_poll :
		*ptr++ = t_data_last;	/* t_poll is a t_data_last without data field */
		*ptr++ = 1;		
		*ptr++  = tcid;
		iRet = 3;
		break;
			
	case t_sb :
		iRet = 0;
		break;
			
	case t_data_last :
	case t_data_more :
		*ptr++ = tpduTag;
		TRPT_SetLength(ptr, pXpdu->m_du.m_xpdu_tdata.m_len, &lenlen);		/* code the length field */
		ptr += lenlen;   	
		*ptr++ = tcid;
		memcpy(ptr, pXpdu->m_du.m_xpdu_tdata.m_pbData, pXpdu->m_du.m_xpdu_tdata.m_len-1); /* sub tcid length : 1 byte */			
		ptr += (pXpdu->m_du.m_xpdu_tdata.m_len-1);
		iRet = 1 + lenlen + pXpdu->m_du.m_xpdu_tdata.m_len;
		break;

	case t_rcv:
	case create_t_c :
	case delete_t_c :
	case d_t_c_reply :
	case request_t_c :
	case c_t_c_reply : ///pmy
		*ptr++ = tpduTag;
		*ptr++ = 1;		
		*ptr++  = tcid;
		iRet = 3;
		break;
		
	case new_t_c :
		*ptr++ = tpduTag;
		*ptr++ = 2;		
		*ptr++ = tcid;
		*ptr++  = pXpdu->m_du.m_xpdu_newtc.m_newTcid;
		iRet = 4;
		break;
			
	case t_c_error :
		*ptr++ = tpduTag;
		*ptr++ = 2;		
		*ptr++ = tcid;
		*ptr++  = pXpdu->m_du.m_xpdu_tcerror.m_errcode;
		iRet = 4;
		break;
			
	default :     
		SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_Code() - Unknown Tag 0x%02X\r\n", tpduTag);
		iRet = 0 ; //-1 modify by pmy
		break;
	}
	
	if (iRet > 0)
	{
		SM_TRACE_BYTES(TRMOD_TRANS, TRLEV_NOTIFY, pbTpdu, iRet, "TRPT_Code() - code tpdu:");
	}

	SM_TRACE_RETURN(TRMOD_TRANS, "TRPT_Code() - return,iRet=%d\r\n", iRet);
	return iRet;				/* return the length of TPDU */
}


/* ======================================================================== */
/* NAME : TRPT_Decode						 								*/
/* 									    									*/
/* DESCRIPTION : decode a TPDU												*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		tpdu	: pointer to TPDU buffer to decode							*/
/*		len		: length of TPDU buffer to decode							*/
/*		tcid	: transport connection										*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*		tpduTag		: type of TPDU												*/
/*		pXpdu	: parameters dependent of the tpduTag							*/
/*									    									*/
/* RETURN CODE								    							*/
/*		 -1 : error while decoding											*/
/*		> 0 : length of decoded TPDU 										*/
/*									  										*/
/* ======================================================================== */
unsigned long TRPT_Decode(unsigned char *pbTpdu, unsigned long len, 
			unsigned char tcid, unsigned char *tpduTag, 
			xpdu_t *pXpdu)
{            
	unsigned char *ptr;		/* pointer to TPDU 				*/
	unsigned long length;	/* length of TPDU data field 	*/
	unsigned short lenlen;	/* length of the length field	*/

	SM_TRACE_ENTRY(TRMOD_TRANS, "TRPT_Decode() - entry,pbTpdu=0x%08X,len=%d,"
					"tcid=%d,tpduTag=0x%08X,pXpdu=0x%08X\r\n",
					pbTpdu, len, tcid, tpduTag, pXpdu);

	ptr = pbTpdu;
	*tpduTag = *ptr++;							/* TPDU's type 	*/
	if (pXpdu)
		pXpdu->m_xpdu_tag = *tpduTag;
	if (TRPT_GetLength(ptr, &length, &lenlen) < 0)	/* decode and get the length field */
	{
		SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_Decode() - get length field failed\r\n");
		return 0;
	}

	//SM_TRACE_BYTES(TRMOD_TRANS, TRLEV_NOTIFY, pbTpdu, len, 
	//			"TRPT_Decode() - decode tpdu[tpduTag=%s(0x%02X),lenfield=%d]:",
	//			XMSG_NAME(*tpduTag), *tpduTag, length);

	ptr += lenlen;

	if (*ptr != tcid)	//pmy ,???					/* Test the tcid */ 
	{
		SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_Decode() - error tcid=%d defferent, *ptr=%d\r\n", tcid, *ptr);
		return 0;
	}
	ptr++;
			
	switch(*tpduTag) 
	{  
	case t_sb :
		pXpdu->m_du.m_xpdu_tsb.m_SBflag = *ptr & 0x80;	/* don't control the reserved field which must be set to 0 */
		//if (pXpdu->m_du.m_xpdu_tsb.m_SBflag)
		//	SM_TRACE_INFO(TRMOD_TRANS, "TRPT_Decode() - tsb with data(0x%02X)\r\n", *ptr);
		break;
			
	case t_data_last :
	case t_data_more :
		pXpdu->m_du.m_xpdu_tdata.m_pbData = ptr;
		pXpdu->m_du.m_xpdu_tdata.m_len   = length - 1;
		//SM_TRACE_INFO(TRMOD_TRANS, "TRPT_Decode() - datalen is 0x%d\r\n", pXpdu->m_du.m_xpdu_tdata.m_len);
		break;
					
	case c_t_c_reply :
	case delete_t_c :
	case d_t_c_reply :
	case request_t_c :		/* no more informations */
	case create_t_c:  //pmy 
	case t_rcv:  //pmy
		break;
			
	default : 
		SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_Decode() - unkown tpdu_tag=0x%02X\r\n", *tpduTag);
		return 0;		/* Error : unknown tpdu */
		break;						
	}

	SM_TRACE_RETURN(TRMOD_TRANS, "TRPT_Decode() - return,len=%d\r\n", length + lenlen + 1);
	return length + lenlen + 1; /* maybe less than len since t_sb can follow the first tpdu */	
}

//add by pmy
unsigned long TRPT_XmsgDecode(xmsg_t* pXmsg, unsigned char *pbTpduTag, 
					unsigned char* pbTcid, xpdu_t *pXpdu)
{				
	unsigned char 	tpduTag = 0;
	unsigned char 	tcid = 0;
	unsigned long 	tpduLen = 0;
	xpdu_t		xpdu;
	xpdu_t*		pInnerXpdu = NULL;

	if (pbTpduTag) *pbTpduTag = 0;
	if (pbTcid) *pbTcid = 0;
	if (pXpdu)
	{
		memset(pXpdu, 0x00, sizeof(xpdu_t));
		pInnerXpdu = pXpdu;
	}
	else
	{
		memset(&xpdu, 0x00, sizeof(xpdu));
		pInnerXpdu = &xpdu;
	}
	
	if (!pXmsg)
		return 0;
	
	if (pXmsg->m_type != TPDU)
		return 0;

	tpduLen = TRPT_Decode(pXmsg->m_bd.m_tpdu.m_pbTpdu, pXmsg->m_bd.m_tpdu.m_len, 
						pXmsg->m_bd.m_tpdu.m_tcid, &tpduTag, pInnerXpdu);
	if (tpduLen <= 0)
	{
		SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_XmsgDecode() - Decode Error while decoding a SPDU "
					"tag=0x%x tcid=%d tpduLen=%d\r\n", tpduTag, *pbTcid, tpduLen);			
		return 0;
	}
	
	if (pbTpduTag) *pbTpduTag = tpduTag;
	if (pbTcid) *pbTcid = pXmsg->m_bd.m_tpdu.m_tcid; //pmy ,???
	if (pXpdu) *pXpdu = *pInnerXpdu;
	
	return tpduLen;
}


/* ======================================================================== */
/* NAME : TRPT_SetLength					 				*/
/* 									    			*/
/* DESCRIPTION : code the length field in TPDU						*/
/*												*/
/* INPUT PARAMETERS :							    		*/
/*		ptr : 	 TPDU to code								*/
/*		length : length to code							*/
/*									 			*/
/* OUTPUT PARAMETERS :							   		*/
/*		lenlen : length field length						*/
/*												*/
/* NOTE :											*/
/* 		The MOST SIGNIFICANT BYTE is positionned first in the TPDU.		*/
/*									    			*/
/* RETURN CODE								    		*/
/* ======================================================================== */
void TRPT_SetLength(unsigned char *ptr, unsigned long length, unsigned short *lenlen)
{          
	if (length <= 127)
	{
		*ptr = (unsigned char)length;
		*lenlen = 1;
	}
	else
	{
		if (length <= 255)
		{
			*ptr = 0x81;
			*lenlen = 2;    /* length field size = 1 */
			*(ptr+1) = (unsigned char)length;
		}
		else if (length <= 65535)
		{
			*ptr = 0x82;		/* length field size = 2 */
			*lenlen = 3;
			*(ptr+1) = (unsigned char) (length >> 8);
			*(ptr+2) = (unsigned char) (length & 0x00FF);
		}
		else
		{
			SM_TRACE_ERROR(TRMOD_TRANS,"TRPT_SetLength() - too big length=%d\r\n", length);
		}
	}

	return;
}


/* ======================================================================== */
/* NAME : TRPT_GetLength					 				*/
/* 												*/
/* DESCRIPTION : decode the length field in TPDU					*/
/* 									    			*/
/* INPUT PARAMETERS :									*/
/*		ptr : 	 TPDU to decode							*/
/*												*/
/* OUTPUT PARAMETERS :									*/
/*		length : length field value						*/
/*		lenlen : length field length						*/
/*												*/
/* NOTE :											*/
/* 		The MOST SIGNIFICANT BYTE is positionned first in the TPDU.		*/
/*												*/
/* RETURN CODE										*/
/*		  1 : Success									*/
/*		 -1 : too big value	(> 65535)						*/
/*									  			*/
/* ======================================================================== */
int TRPT_GetLength(unsigned char *ptr, unsigned long *length, unsigned short *lenlen)
{   
	int iRet;	/* return code */
          
	iRet    = 1; 

	if ((*ptr & 0x80) == 0x80)
	{							/* more than 1 byte 		  */
		*lenlen = *ptr & 0x7f;				
		if (*lenlen == 1)		/* value coded with 1 byte    */
		{
			*length = *(ptr+1);
			(*lenlen)++;	    /* adjust length field length */
		}
		else
		{
			if (*lenlen == 2)   /* value coded with 2 bytes   */
			{
				*length = (((unsigned long)(*(ptr+1))) << 8) +
									(unsigned long)(*(ptr+2));
				(*lenlen)++;		/* adjust length field length */	
			}
			else if (*lenlen == 3) /*branch added by hszhang*/
			{
				*length = ((unsigned long)(*(ptr + 1)) << 16) | ((unsigned long)(*(ptr + 2)) << 8) | ((unsigned long)(*(ptr + 3)));
			}
			else if (*lenlen == 4)/*branch added by hszhang*/
			{
				*length = ((unsigned long)(*(ptr + 1)) << 24) | ((unsigned long)(*(ptr + 2)) << 16) | ((unsigned long)(*(ptr + 3)) << 8) | ((unsigned long)(*(ptr + 4)));
			}
			else
			{
				SM_TRACE_ERROR(TRMOD_TRANS, "TRPT_GetLength() - too big lenlen value=%d\r\n",*lenlen);
				iRet = -1;		/* too big value 			  */
			}
		}
	}
	else
	{
		*length = *ptr;
		*lenlen = 1;
	}           
	
	return iRet;
}

